# package deb

# import (
# 	"archive/tar"
# 	"bufio"
# 	"compress/bzip2"
# 	"compress/gzip"
# 	"fmt"
# 	"io"
# 	"os"
# 	"strings"

# 	"github.com/h2non/filetype/matchers"
# 	ar "github.com/mkrautz/goar"
# 	"github.com/pkg/errors"

# 	"github.com/aptly-dev/aptly/pgp"
# 	"github.com/kjk/lzma"
# 	"github.com/klauspost/compress/zstd"
# 	"github.com/smira/go-xz"
# )
from typing import List,Dict,Tuple
# // Source kinds
# const (

# from apt.debfile import *
from io import StringIO
from .formatp import *
import unix_ar
# )

# type parseQuery def(string) (PackageQuery, error)


import contextlib
import io
import tarfile
import tempfile
from pyzstd import decompress_stream

# @contextlib.contextmanager
def ZstdTarReader(name, *, zstd_dict=None, option=None, **kwargs):
    # with io.open(name, 'rb') as ifh:
    tmp_file=tempfile.TemporaryFile()
    decompress_stream(name, tmp_file,
                        zstd_dict=zstd_dict, option=option)
    tmp_file.seek(0)
    tar= tarfile.TarFile(fileobj=tmp_file, **kwargs) 
    return tar
        

# // GetControlFileFromDeb reads control file from deb package
def GetControlFileFromDeb(packageFile :str) ->Stanza:
    # file= unix_ar.open(packageFile)
    # if err is not None  {
    # 	return None, err
    # }
    # defer file.Close()

    library = unix_ar.open(packageFile)
    for header in library.infolist():
        # header, err = library.Next()

        # if err == io.EOF {
        # 	return None, fmt.Errorf("unable to find control.tar.* part in package %s", packageFile)
        # }
        # if err is not None  {
        # 	return None, fmt.Errorf("unable to read .deb archive %s: %s", packageFile, err)
        # }

        # // As per deb(5) version 1.19.0.4 the control file may be:
        # // - control.tar (since 1.17.6)
        # // - control.tar.gz
        # // - control.tar.xz (since 1.17.6)
        # // Look for all of the above and uncompress as necessary.
        headerName=header.name.decode()
        if headerName.startswith( "control.tar") :
            # bufReader = bufio.NewReader(library)
            # bufReader=None
            tarInput=None
            
            if headerName== "control.tar":
                tarInput = tarfile.open(fileobj=library.open("control.tar"),mode='r')
            elif headerName =="control.tar.gz":
                ungzip= tarfile.open(fileobj=library.open("control.tar.gz"),mode='r:gz')#(bufReader)
                # if err is not None  :
                #     return None, errors.Wrapf(err, "unable to ungzip %s from %s", header.name, packageFile)
                
                # defer ungzip.Close()
                tarInput = ungzip
            elif headerName == "control.tar.xz":
                unxz = tarfile.open(fileobj=library.open("control.tar.xz"),mode='r:xz')
                # if err is not None  :
                #     return None, errors.Wrapf(err, "unable to unxz %s from %s", header.name, packageFile)
                
                # defer unxz.Close()
                tarInput = unxz
            elif headerName== "control.tar.zst":
                
                unzstd = ZstdTarReader(library.open("control.tar.zst"))
                # if err is not None  :
                #     return None, errors.Wrapf(err, "unable to unzstd %s from %s", header.name, packageFile)
                
                # defer unzstd.Close()
                
                tarInput = unzstd
            else:
                return None, "unsupported tar compression in {}: {}".format( packageFile, header.name)
            

            untar =tarInput
            
            for tarHeader in untar.getmembers():
                # tarHeader, err = untar.Next()
                # if err == io.EOF {
                #     return None, fmt.Errorf("unable to find control file in %s", packageFile)
                # }
                # if err is not None  {
                #     return None, fmt.Errorf("unable to read .tar archive from %s. Error: %s", packageFile, err)
                # }
                tarHeaderName=tarHeader.name
                if tarHeaderName == "./control" or tarHeaderName == "control" :
                    reader = NewControlFileReader(untar.extractfile(tarHeader), False, False)
                    stanza, err = reader.ReadStanza()
                    if err is not None  :
                        untar.close()
                        return None, err
                    
                    untar.close()
                    return stanza, None
                
            
        
    


# // GetControlFileFromDsc reads control file from dsc package
def GetControlFileFromDsc(dscFile :str, verifier )->Tuple [Stanza, str] :
    file= open(dscFile)

    isClearSigned= verifier.IsClearSigned(file)
    file.Seek(0, 0)
    if isClearSigned :
        text = verifier.ExtractClearsigned(file)
    else :
        text = file
    

    reader = NewControlFileReader(text, False, False)
    stanza= reader.ReadStanza()

    return stanza



# // GetContentsFromDeb returns list of files installed by .deb package
def GetContentsFromDeb( packageFile :str) ->Tuple[List[str], str] :
    library = unix_ar.open(packageFile)
    for header in library.infolist():
        # if err == io.EOF {
        #     return None, fmt.Errorf("unable to find data.tar.* part in %s", packageFile)
        # }
        # if err is not None  {
        #     return None, errors.Wrapf(err, "unable to read .deb archive from %s", packageFile)
        # }
        headerName:str=header.name.decode()
        if headerName.startswith( "data.tar") :
            # bufReader = bufio.NewReader(library)
            # signature, err = bufReader.Peek(270)
            
            
            # if err is None  {
            #     isTar = matchers.Tar(signature)
            # }

            tarInput=None# io.Reader

            
            if headerName== "data.tar":
                tarInput = tarfile.open(fileobj=library.open("data.tar"),mode='r')
            elif headerName== "data.tar.gz":
                isTar :bool=tarfile.is_tarfile(library.open("data.tar.gz"))
                if isTar :
                    tarInput = tarfile.open(fileobj=library.open("data.tar.gz"),mode='r')
                else :
                    ungzip = tarfile.open(fileobj=library.open("data.tar.gz"),mode='r:gz')
                    # if err is not None  {
                    #     return None, errors.Wrapf(err, "unable to ungzip data.tar.gz from %s", packageFile)
                    # }
                    # defer ungzip.Close()
                    tarInput = ungzip
                
            elif headerName== "data.tar.bz2":
                tarInput = tarfile.open(fileobj=library.open("data.tar.bz"),mode='r:bz')
            elif headerName== "data.tar.xz":
                unxz = tarfile.open(fileobj=library.open("data.tar.xz"),mode='r:xz')
                # if err is not None  {
                #     return None, errors.Wrapf(err, "unable to unxz data.tar.xz from %s", packageFile)
                # }
                # defer unxz.Close()
                tarInput = unxz
            elif headerName== "data.tar.lzma":
                unlzma = tarfile.open(fileobj=library.open("data.tar.xz"),mode='r:xz')
                # defer unlzma.Close()
                tarInput = unlzma
            elif headerName== "data.tar.zst":
                unzstd = ZstdTarReader(library.open("data.tar.zst"))
                # if err is not None  {
                #     return None, errors.Wrapf(err, "unable to unzstd %s from %s", header.name, packageFile)
                # }
                # defer unzstd.Close()
                tarInput = unzstd
            else:
                return None, "unsupported tar compression in {}: {}".format( packageFile, header.name)
            

            # untar = tar.NewReader(tarInput)
            results :List[str]=[]
            untar =tarInput
            for tarHeader in untar.getmembers():
                # tarHeader, err = untar.Next()
                # if err == io.EOF {
                #     return results, None
                # }
                # if err is not None  {
                #     return None, errors.Wrapf(err, "unable to read .tar archive from %s", packageFile)
                # }
                tarHeaderName=tarHeader.name
                if tarHeader.isdir():
                    continue
                

                tarHeaderName = tarHeaderName[2:].strip( "./")
                results . append( tarHeaderName)
            untar.close()
            return results